package cn.bandeqing.worker.rpc.impl;

import cn.bandeqing.base.domain.AdminUserStore;
import cn.bandeqing.base.domain.CurrentAdminUser;
import cn.bandeqing.base.domain.CurrentWorkerUser;
import cn.bandeqing.base.resp.Resp;
import cn.bandeqing.base.resp.Table;
import cn.bandeqing.base.util.PasswordUtil;
import cn.bandeqing.frame.exception.CodeException;
import cn.bandeqing.stp.StpAdminUtil;
import cn.bandeqing.stp.StpWorkerUtil;
import cn.bandeqing.worker.entity.Worker;
import cn.bandeqing.worker.entity.WorkerLevel;
import cn.bandeqing.worker.entity.WorkerStatus;
import cn.bandeqing.worker.req.*;
import cn.bandeqing.worker.resp.WalletListResp;
import cn.bandeqing.worker.resp.WorkerRegisterResp;
import cn.bandeqing.worker.resp.WorkerTable;
import cn.bandeqing.worker.resp.WorkerWalletResp;
import cn.bandeqing.worker.rpc.IWorkRpc;
import cn.bandeqing.worker.service.IWorkerService;
import cn.bandeqing.workerEquipment.entity.WorkerEquipment;
import cn.bandeqing.workerEquipment.service.IWorkerEquipmentService;
import cn.bandeqing.workerWallet.entity.WorkerWallet;
import cn.bandeqing.workerWallet.service.IWorkerWalletService;
import cn.bandeqing.workerWalletRecord.entity.WorkerWalletRecord;
import cn.bandeqing.workerWalletRecord.entity.WwrStatus;
import cn.bandeqing.workerWalletRecord.entity.WwrType;
import cn.bandeqing.workerWalletRecord.service.IWorkerWalletRecordService;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.query.QueryWrapper;
import io.github.linpeilie.Converter;
import jakarta.annotation.Resource;
import org.apache.dubbo.config.annotation.DubboService;
import org.dromara.hutool.core.collection.CollUtil;
import org.dromara.hutool.core.data.IdcardUtil;
import org.dromara.hutool.core.data.PhoneUtil;
import org.dromara.hutool.core.lang.Assert;
import org.dromara.hutool.core.text.StrUtil;
import org.dromara.hutool.core.util.RandomUtil;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

import static cn.bandeqing.worker.entity.table.WorkerTableDef.WORKER;
import static cn.bandeqing.workerWallet.entity.table.WorkerWalletTableDef.WORKER_WALLET;
import static cn.bandeqing.workerWalletRecord.entity.table.WorkerWalletRecordTableDef.WORKER_WALLET_RECORD;

@DubboService
public class WorkRpcImpl implements IWorkRpc {

    @Resource
    private IWorkerService workerService;
    @Resource
    private IWorkerWalletService workerWalletService;
    @Resource
    private IWorkerWalletRecordService workerWalletRecordService;
    @Resource
    private IWorkerEquipmentService workerEquipmentService;
    @Resource
    private Converter converter;

    @Override
    public Resp<Table<WorkerTable>> table(WorkerTableReq req) {
        QueryWrapper qw = QueryWrapper.create()
                .where(WORKER.WORKER_ID.eq(req.getWorkerId()))
                .where(WORKER.WORKER_UUID.eq(req.getWorkerUuid()))
                .where(WORKER.WORKER_NICK_NAME.eq(req.getWorkerNickName()))
                .where(WORKER.WORKER_REAL_NAME.eq(req.getWorkerRealName()))
                .where(WORKER.WORKER_ID_CARD_NUMBER.eq(req.getWorkerIdCardNumber()))
                .where(WORKER.WORKER_TYPE.eq(req.getWorkerType()))
                .where(WORKER.WORKER_PHONE.eq(req.getWorkerPhone()))
                .where(WORKER.WORKER_STATUS.eq(req.getWorkerStatus()))
                .where(WORKER.WORKER_EMERGENCY_CONTACT.eq(req.getWorkerEmergencyContact()))
                .where(WORKER.WORKER_EMERGENCY_CONTACT_PHONE.eq(req.getWorkerEmergencyContactPhone()))
                .where(WORKER.WORKER_NATION.eq(req.getWorkerNation()))
                .where(WORKER.WORKER_SEX.eq(req.getWorkerSex()))
                .where(WORKER.WORKER_ADDRESS.eq(req.getWorkerAddress()))
                .where(WORKER.WORKER_CITY.eq(req.getWorkerCity()))
                .where(WORKER.STORE_ID.eq(req.getStoreId()))
                .orderBy(WORKER.WORKER_ID.desc());

        if (req.getStoreId() == null) {
            CurrentAdminUser current = StpAdminUtil.getCurrent();
            if (current.checkStoreAccount()) {
                // 店铺账号 只能查询店铺下的权限
                qw.where(WORKER.STORE_ID.in(current.getStores().stream().map(AdminUserStore::getStoreId).toList()));
            }
        }

        Page<WorkerTable> page = workerService.pageAs(Page.of(req.getCurrent(), req.getPageSize()), qw, WorkerTable.class);
        return Resp.success(Table.of(page.getRecords(), page.getTotalRow()));
    }

    @Override
    @Transactional
    public void saveOrUpdate(WorkerSaveOrUpdateReq req) {
        Worker worker = converter.convert(req, Worker.class);
        boolean add = worker.getWorkerId() == null;
        if (add) {
            worker.setWorkerStatus(WorkerStatus.register);
            worker.setWorkerLevel(WorkerLevel.internship);
            worker.setWorkerUuid(RandomUtil.randomNumbers(8));
            worker.setWorkerLoginPasswordSalt(RandomUtil.randomNumbers(6));
            worker.setWorkerLoginPassword(PasswordUtil.pwdSalt(req.getWorkerPhone(), worker.getWorkerLoginPassword(), worker.getWorkerLoginPasswordSalt()));
        }

        if (CollUtil.isNotEmpty(req.getWorkerSkillsList())) {
            worker.setWorkerSkills(CollUtil.join(req.getWorkerSkillsList(), ","));
        } else {
            worker.setWorkerSkills(StrUtil.EMPTY);
        }

        if (CollUtil.isNotEmpty(req.getWorkerToolsList())) {
            worker.setWorkerTools(CollUtil.join(req.getWorkerToolsList(), ","));
        } else {
            worker.setWorkerTools(StrUtil.EMPTY);
        }

        Assert.isTrue(workerService.saveOrUpdate(worker), () -> new CodeException("workerService.saveOrUpdate(worker)"));

        if (add) {
            boolean save = workerWalletService.save(WorkerWallet.builder()
                    .workerId(worker.getWorkerId())
                    .workerNickName(req.getWorkerNickName())
                    .build());
            Assert.isTrue(save, () -> new CodeException("工作人员钱包初始化失败"));
        } else {
            // 修改用户后踢出用户在线
            StpWorkerUtil.logout(worker.getWorkerId());
        }
    }

    @Override
    @Transactional
    public Resp<WorkerRegisterResp> register(WorkerRegisterReq req) {
        Worker worker = converter.convert(req, Worker.class);
        worker.setWorkerUuid(RandomUtil.randomNumbers(8));
        worker.setWorkerStatus(WorkerStatus.register);
        worker.setWorkerLevel(WorkerLevel.internship);
        worker.setCreateUserId(0L);
        worker.setCreateUserName(req.getWorkerRealName());
        worker.setWorkerNickName(req.getWorkerRealName());
        worker.setWorkerLoginPasswordSalt(RandomUtil.randomNumbers(6));
        worker.setWorkerLoginPassword(PasswordUtil.pwdSalt(req.getWorkerPhone(), "123456", worker.getWorkerLoginPasswordSalt()));
        Assert.isTrue(workerService.save(worker), () -> new CodeException("workerService.save(worker)"));

        boolean save = workerWalletService.save(WorkerWallet.builder()
                .workerId(worker.getWorkerId())
                .workerNickName(req.getWorkerRealName())
                .createUserId(0L)
                .createUserName(req.getWorkerRealName())
                .build());
        Assert.isTrue(save, () -> new CodeException("工作人员钱包初始化失败"));
        return Resp.success(new WorkerRegisterResp(worker.getWorkerId()));
    }

    @Override
    public Resp<Void> login(WorkerLoginReq req) {
        Worker worker = workerService.getOne(QueryWrapper.create().where(WORKER.WORKER_PHONE.eq(req.getWorkerPhone())));
        Assert.notNull(worker, () -> new CodeException("用户名或密码错误"));

        Assert.isTrue(WorkerStatus.pass.equals(worker.getWorkerStatus()), () -> new CodeException("用户状态不是启用状态，请联系管理员启用后登录"));

        String pwdSalt = PasswordUtil.pwdSalt(worker.getWorkerPhone(), req.getWorkerLoginPwd(), worker.getWorkerLoginPasswordSalt());
        Assert.isTrue(pwdSalt.equals(worker.getWorkerLoginPassword()), () -> new CodeException("用户名或密码错误"));

        CurrentWorkerUser currentWorkerUser = converter.convert(worker, CurrentWorkerUser.class);
        currentWorkerUser.setWorkerPhone(PhoneUtil.hideBetween(currentWorkerUser.getWorkerPhone()).toString());
        currentWorkerUser.setWorkerIdCardNumber(IdcardUtil.hide(currentWorkerUser.getWorkerIdCardNumber(), 7, 15));

        StpWorkerUtil.login(currentWorkerUser);
        return Resp.success();
    }

    @Override
    public Resp<Void> resetPwd(ResetPwdReq req) {
        String salt = RandomUtil.randomNumbers(6);
        boolean b = workerService.updateById(Worker.builder()
                .workerId(req.getWorkerId())
                .workerLoginPasswordSalt(salt)
                .workerLoginPassword(PasswordUtil.pwdSalt(req.getWorkerPhone(), "123456", salt))
                .build());
        Assert.isTrue(b, () -> new CodeException("密码重置失败"));
        return Resp.success();
    }

    @Override
    public void modifyStatus(ModifyStatusReq req) {
        Worker worker = workerService.getOne(QueryWrapper.create()
                .select(WORKER.WORKER_STATUS).where(WORKER.WORKER_ID.eq(req.getWorkerId())));

        Assert.isFalse(worker.getWorkerStatus().getValue().equals(req.getWorkerStatus()), () -> new CodeException("不能修改成当前状态"));

        Assert.isFalse(req.getWorkerStatus().equals(WorkerStatus.register.getValue()), () -> new CodeException("不能修改成注册状态"));

        Worker modify = converter.convert(req, Worker.class);

        Assert.isTrue(workerService.updateById(modify), () -> new CodeException("workerService.updateById(Worker.builder().build())"));

    }

    @Override
    public void modifyLevel(ModifyLevelReq req) {
        Worker modify = converter.convert(req, Worker.class);

        Assert.isTrue(workerService.updateById(modify), () -> new CodeException("workerService.updateById(Worker.builder().build())"));
    }

    @Override
    public Resp<WorkerWalletResp> wallet() {
        WorkerWalletResp wwr = workerWalletService.getOneAs(QueryWrapper.create()
                .where(WORKER_WALLET.WORKER_ID.eq(StpWorkerUtil.getLoginId())), WorkerWalletResp.class);
        return Resp.success(wwr);
    }

    @Override
    public Resp<List<WalletListResp>> walletList(WalletListReq req) {
        List<WalletListResp> walletListResps = workerWalletRecordService.listAs(QueryWrapper.create()
                .where(WORKER_WALLET_RECORD.WORKER_ID.eq(StpWorkerUtil.getLoginId()))
                .limit((req.getPage() - 1) * req.getSize(), req.getSize())
                .orderBy(WORKER_WALLET_RECORD.WWR_ID.desc()), WalletListResp.class);
        return Resp.success(walletListResps);
    }

    @Override
    public Resp<Void> modifyPwd(ModifyPwdReq req) {
//        Worker worker = workerService.getById(StpAdminUtil.getLoginId());
        Long workerId = StpWorkerUtil.getLoginId();
        Worker worker = workerService.getOne(QueryWrapper.create()
                .select(WORKER.WORKER_PHONE, WORKER.WORKER_LOGIN_PASSWORD_SALT, WORKER.WORKER_LOGIN_PASSWORD)
                .where(WORKER.WORKER_ID.eq(workerId)));

        String oldPwdSalt = PasswordUtil.pwdSalt(worker.getWorkerPhone(), req.getOldPwd(), worker.getWorkerLoginPasswordSalt());
        Assert.isTrue(oldPwdSalt.equals(worker.getWorkerLoginPassword()), () -> new CodeException("旧密码错误"));

        String random = RandomUtil.randomNumbers(6);

        boolean b = workerService.updateById(Worker.builder()
                .workerId(workerId)
                .workerLoginPassword(PasswordUtil.pwdSalt(worker.getWorkerPhone(), req.getNewPwd(), random))
                .workerLoginPasswordSalt(random)
                .build());
        Assert.isTrue(b, () -> new CodeException("密码更新失败"));

        // 退出
        StpWorkerUtil.logout();

        return Resp.success();
    }

    @Override
    @Transactional
    public Resp<Void> uploadEquipment(UploadEquipmentReq req) {

        WorkerEquipment we = converter.convert(req, WorkerEquipment.class);

        CurrentWorkerUser current = StpWorkerUtil.getCurrent();

        we.setWorkerId(current.getWorkerId());
        we.setWorkerName(current.getWorkerNickName());

        Assert.isTrue(workerEquipmentService.save(we), CodeException::new);

        if (StrUtil.isNotBlank(we.getDeviceCid())) {
            workerService.updateById(Worker.builder()
                    .workerId(current.getWorkerId())
                    .workerCid(we.getDeviceCid())
                    .build());
        }

        return Resp.success();
    }

    @Override
    @Transactional
    public synchronized Resp<Void> withdraw(WithdrawReq req) {
        WorkerWallet ww = workerWalletService.getById(StpWorkerUtil.getLoginId());

        Assert.isTrue(ww.getWorkerBalance() > req.getMoney(), () -> new CodeException("余额不足"));

        Double workerBalance = ww.getWorkerBalance();
        Double after = workerBalance - req.getMoney();

        Assert.isTrue(workerWalletService.updateById(WorkerWallet.builder()
                .workerId(ww.getWorkerId())
                .workerBalance(after)
                .workerTotalCashMoney(ww.getWorkerTotalCashMoney() + req.getMoney())
                .build()), CodeException::new);

        Assert.isTrue(workerWalletRecordService.save(WorkerWalletRecord.builder()
                .workerId(ww.getWorkerId())
                .workerNickName(ww.getWorkerNickName())
                .wwrType(WwrType.cash)
                .beforeMoney(workerBalance)
                .changeMoney(req.getMoney())
                .afterMoney(after)
                .wwrStatus(WwrStatus.await)
                .wwrDesc("提现申请")
                .build()));

        return Resp.success();
    }

}
